package com.vc.service;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import redis.clients.jedis.Jedis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.googlecode.ehcache.annotations.Cacheable;

import core.Constants;
import core.dto.MarketDTO;
import core.dto.TradeDTO;
import core.util.JedisUtil;
import core.util.SerializeUtil;
import core.util.TimeZoneUtil;

@Component
@SuppressWarnings("unchecked")
public class RemoteService {
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	public List<MarketDTO> findAllMarkets() {
		Jedis jedis = JedisUtil.getJedis();
		try {
			return (List<MarketDTO>) SerializeUtil.deserialize(jedis.get(Constants.allMarkets));
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		} finally {
			JedisUtil.returnJedis();
		}
		return null;
	}
	
	public MarketDTO findMarketById(String marketId) {
		Jedis jedis = JedisUtil.getJedis();
		try {
			byte[] bytes = jedis.hget(Constants.MarketInfoMap.name, (Constants.MarketInfoMap.keyPrefix + marketId).getBytes());
			MarketDTO marketInfo = (MarketDTO) SerializeUtil.deserialize(bytes);
			if (marketInfo != null) {
				marketInfo.setLasttradetime(TimeZoneUtil.asChinaTime(marketInfo.getLasttradetime()));
				return marketInfo;
			}
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		} finally {
			JedisUtil.returnJedis();
		}
		return null;
	}
	
	@Cacheable(cacheName = "marketOrderCache")
	public List<TradeDTO> findBuyOrders(String code, String marketId) {
		Jedis jedis = JedisUtil.getJedis();
		try {
			String content = jedis.hget(Constants.BuyOrdersMap.name, Constants.BuyOrdersMap.keyPrefix + marketId);
			return getTradeOrders(code, content);
		} finally {
			JedisUtil.returnJedis();
		}
	}
	
	@Cacheable(cacheName = "marketChartCache")
	public String findRawChartData(String marketId) {
		Jedis jedis = JedisUtil.getJedis();
		try {
			return jedis.hget(Constants.MarketChartMap.name, Constants.MarketChartMap.keyPrefix + marketId);
		} finally {
			JedisUtil.returnJedis();
		}
	}

	@Cacheable(cacheName = "marketOrderCache")
	public String findRawBuyOrders(String marketId) {
		Jedis jedis = JedisUtil.getJedis();
		try {
			return jedis.hget(Constants.BuyOrdersMap.name, Constants.BuyOrdersMap.keyPrefix + marketId);
		} finally {
			JedisUtil.returnJedis();
		}
	}

	@Cacheable(cacheName = "marketOrderCache")
	public String findRawSellOrders(String marketId) {
		Jedis jedis = JedisUtil.getJedis();
		try {
			return jedis.hget(Constants.SellOrdersMap.name, Constants.SellOrdersMap.keyPrefix + marketId);
		} finally {
			JedisUtil.returnJedis();
		}
	}

	@Cacheable(cacheName = "marketOrderCache")
	public String findRawHisOrders(String marketId) {
		Jedis jedis = JedisUtil.getJedis();
		try {
			return jedis.hget(Constants.HisOrdersMap.name, Constants.HisOrdersMap.keyPrefix + marketId);
		} finally {
			JedisUtil.returnJedis();
		}
	}

	@Cacheable(cacheName = "marketOrderCache")
	public List<TradeDTO> findSellOrders(String code, String marketId) {
		Jedis jedis = JedisUtil.getJedis();
		try {
			String content = jedis.hget(Constants.SellOrdersMap.name, Constants.SellOrdersMap.keyPrefix + marketId);
			return getTradeOrders(code, content);
		} finally {
			JedisUtil.returnJedis();
		}
	}

	@Cacheable(cacheName = "marketOrderCache")
	public List<TradeDTO> findHistoryOrders(String code, String marketId) {
		Jedis jedis = JedisUtil.getJedis();
		try {
			String content = jedis.hget(Constants.HisOrdersMap.name, Constants.HisOrdersMap.keyPrefix + marketId);
			return getHisOrders(code, content);
		} finally {
			JedisUtil.returnJedis();
		}
	}
	
	public double findBtcPrice() {
		Jedis jedis = JedisUtil.getJedis();
		try {
			return Double.valueOf(jedis.hget(Constants.PriceMap.name, Constants.PriceMap.btcPrice));
		} finally {
			JedisUtil.returnJedis();
		}
	}
	
	public double findLtcPrice() {
		Jedis jedis = JedisUtil.getJedis();
		try {
			return Double.valueOf(jedis.hget(Constants.PriceMap.name, Constants.PriceMap.ltcPrice));
		} finally {
			JedisUtil.returnJedis();
		}
	}
	
	//----------------------------------------------------------------------
	// for self usage
	//----------------------------------------------------------------------
	
	protected List<TradeDTO> getTradeOrders(String code, String content) {
		List<TradeDTO> trades = new ArrayList<TradeDTO>();
		Map<String, Object> map = JSON.parseObject(content, Map.class);
		JSONArray array = JSON.parseArray("" + map.get("aaData"));
		
		double base = 1;
		if ("BTC".equals(code)) {
			base = findBtcPrice();
		} else if ("LTC".equals(code)) {
			base = findLtcPrice();
		}
		
		DecimalFormat format = new DecimalFormat(Constants.NUMBER_FORMAT_PATTERN);
		
		for (int i = 0; i < array.size(); i++) {
			String each = "" + array.get(i);
			JSONArray detail = JSON.parseArray(each);
			TradeDTO trade = new TradeDTO();
			double price = Double.valueOf(detail.getString(0));
			double total = Double.valueOf(detail.getString(2));
			trade.setPrice(format.format(price * base));
			trade.setQuantity(detail.getString(1));
			trade.setTotal(format.format(total * base));
			trades.add(trade);
		}
		return trades;
	}
	
	protected List<TradeDTO> getHisOrders(String code, String content) {
		List<TradeDTO> trades = new ArrayList<TradeDTO>();
		Map<String, Object> map = JSON.parseObject(content, Map.class);
		JSONArray array = JSON.parseArray("" + map.get("aaData"));
		
		double base = 1;
		if ("BTC".equals(code)) {
			base = findBtcPrice();
		} else if ("LTC".equals(code)) {
			base = findLtcPrice();
		}
		
		DecimalFormat format = new DecimalFormat(Constants.NUMBER_FORMAT_PATTERN);
		
		for (int i = 0; i < array.size(); i++) {
			String each = "" + array.get(i);
			JSONArray detail = JSON.parseArray(each);
			TradeDTO trade = new TradeDTO();
			double price = Double.valueOf(detail.getString(2));
			double total = Double.valueOf(detail.getString(4));
			trade.setTime(TimeZoneUtil.asChinaTime(detail.getString(0)));
			trade.setType(detail.getString(1));
			trade.setPrice(format.format(price * base));
			trade.setQuantity(detail.getString(3));
			trade.setTotal(format.format(total * base));
			trades.add(trade);
		}
		return trades;
	}
	
}
